package com.xqboss.apps.service.guild;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.domain.guild.Guild;
import com.xqboss.apps.domain.guild.GuildMember;
import com.xqboss.apps.dto.guild.*;
import com.xqboss.apps.enums.consumer.ConsumerTeamRoleEnum;
import com.xqboss.apps.enums.guild.GuildExitStatusEnum;
import com.xqboss.apps.enums.guild.GuildExitTypeEnum;
import com.xqboss.apps.mapper.guild.GuildMapper;
import com.xqboss.apps.vo.guild.*;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.LocalDateUtils;
import com.xqboss.common.utils.StringUtils;
import com.xqboss.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * 公会接口
 *
 * @author wangcong
 * @date 2023-11-01
 */
@Slf4j
@Service
public class GuildService extends ServiceImpl<GuildMapper, Guild> {

    @Autowired
    private ISysUserService userService;
    @Autowired
    private GuildMemberService guildMemberService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;


    //*************************************************************************************************************
    //************************************TODO：下面是后台相关********************************************************
    //*************************************************************************************************************

    /**
     * 创建公会
     * @param userList
     */
    @Transactional(rollbackFor = Exception.class)
    public void add(List<String> userList) throws ExecutionException, InterruptedException {
        //公会用户去重校验
        Set<Long> userIds = userList.stream().map(Long::parseLong).collect(Collectors.toSet());
        Assert.isFalse(userIds.size() != userList.size(),()->new ServiceException("公会用户列表重复"));

        //判断用户列表是否都存在
        userIds.forEach(userId->Assert.isFalse(ObjUtil.isNull(userService.selectUserById(userId)),()->new ServiceException(StringUtils.format("{}用户不存在！", userId))));

        //判断用户列表中是否有用户已创建了公会
        List<Guild> guilds = this.lambdaQuery().select(Guild::getId, Guild::getCreateUserId).in(Guild::getCreateUserId, userIds).list();
        Assert.isFalse(CollUtil.isNotEmpty(guilds),()->new ServiceException("用户[" + guilds.stream().map(Guild::getCreateUserId).map(String::valueOf).collect(Collectors.joining(",")) + "]已创建公会！"));

        //创建公会、会长
        for (Long userId : userIds) {
            CompletableFuture.supplyAsync(() -> {
                //设置这几个属性，其它属性走数据库默认值
                Guild guild = Guild.builder().createUserId(userId).name(RandomUtil.randomString(8)).memberCount(1).build();
                //新增公会
                boolean save = this.save(guild);
                //验证
                Assert.isTrue(save, () -> new ServiceException(String.format("用户%s创建公会失败！", userId)));
                //返回队伍id，用户添加会长信息使用
                return guild.getId();
            }, threadPoolTaskExecutor).thenAccept((guildId) -> {
                //创建公会成员
                GuildMember guildMember = GuildMember.builder().guildId(guildId).userId(userId).role(ConsumerTeamRoleEnum.ADMINISTRATOR).joinTime(LocalDateUtils.getCurrentLocalDateTime()).build();
                //新增会长
                boolean save = this.guildMemberService.save(guildMember);
                //验证
                Assert.isTrue(save, () -> new ServiceException(String.format("用户%s创建会长失败！", userId)));
            }).exceptionally(e->{
                //打印
                log.error("[创建公会、会长异常]",e);
                //抛异常
                throw new ServiceException(e.getMessage());
            }).get();
        }
    }

    /**
     * 公会列表
     * @param dto
     * @return
     */
    public IPage<WebGuildVo> getGuildList(GetGuildListDto<WebGuildVo> dto) {

        return this.getBaseMapper().getGuildList(dto.newPage(),dto);
    }

    /**
     * 公会详情
     * @param id
     * @return
     */
    public GuildDetailVo getGuildDitle(Long id) {
        //获取公会
        Guild guild = this.getById(id);
        Assert.isFalse(ObjUtil.isEmpty(guild),()->new ServiceException("公会不存在"));
        GuildDetailVo vo = BeanUtil.copyProperties(guild, GuildDetailVo.class);
        //获取会员列表
        List<GuildMember> memberList = this.guildMemberService.lambdaQuery()
                .select(GuildMember::getUserId, GuildMember::getJoinTime, GuildMember::getContribution)
                .eq(GuildMember::getGuildId, id)
                .orderByDesc(GuildMember::getJoinTime)
                .list();
        vo.setGuildMember(memberList);
        return vo;
    }

    /**
     * 编辑公会
     * @param dto
     */
    @Transactional(rollbackFor = Exception.class)
    public void editGuild(Guild dto) {
        Assert.isTrue(this.lambdaUpdate()
                .set(Guild::getLevel, dto.getLevel())
                .set(Guild::getMaxNumber, dto.getMaxNumber())
                .set(Guild::getAvatar, dto.getAvatar())
                .eq(Guild::getId, dto.getId())
                .update(),()->new ServiceException("编辑公会失败"));
    }

    /**
     * 公会上下架
     * @param dto
     */
    @Transactional(rollbackFor = Exception.class)
    public void changeSaleable(GuildSaleableDto dto) {
        Assert.isTrue(this.lambdaUpdate()
                .set(Guild::getStatus, dto.getStatus())
                .eq(Guild::getId, dto.getId())
                .update(),()->new ServiceException("公会下架失败"));
    }

    /**
     * 解散公会
     *
     * @param guildId 公会id
     */
    @Transactional(rollbackFor = Exception.class)
    public void guildDissolve(Long guildId) {
        Assert.notNull(this.getById(guildId),()->new ServiceException("公会不存在~"));
        // 执行解散公会逻辑
        boolean update = this.lambdaUpdate()
                .set(Guild::getStatus, 1)
                .set(Guild::getMemberCount, 0)
                .eq(Guild::getId, guildId)
                .update();
        // 验证
        Assert.isTrue(update,()->new ServiceException("解散公会失败~"));
        // 成员退出公会
        boolean update1 = this.guildMemberService.lambdaUpdate()
                .set(GuildMember::getExitTime, LocalDateUtils.getCurrentLocalDateTime())
                .set(GuildMember::getExitStatus, GuildExitStatusEnum.EXIT_ACTIVE_UN)
                .set(GuildMember::getExitType, GuildExitTypeEnum.BACK_DISSOLVE)
                .set(GuildMember::getDelFlag, Boolean.TRUE)
                .eq(GuildMember::getId, guildId)
                .update();
        // 验证
        Assert.isTrue(update1,()->new ServiceException("成员退出失败~"));
    }
}
